5.2 Argumentos Arbitrarios
En muchas situaciones no se conoce de antemano cuántos valores recibirá una función.
Para estos casos, Python permite definir funciones que acepten un número variable de argumentos, tanto posicionales como con nombre.
Esto se logra mediante los operadores * y **, conocidos respectivamente como *args y **kwargs.
Gracias a ellos, una función puede adaptarse a diferentes contextos sin necesidad de definir cada parámetro de forma explícita.
1️⃣ Argumentos posicionales arbitrarios (*args)
Cuando se antepone un asterisco * a un parámetro, Python agrupa todos los argumentos posicionales recibidos en una tupla.
Esto permite que la función acepte una cantidad indefinida de valores.
Sintaxis general
def sumar_todo(*numeros):
"""Suma todos los valores pasados como argumentos."""
total = 0
for n in numeros:
total += n
return total
print(sumar_todo(3, 5, 9))
print(sumar_todo(10, 20, 30, 40))
El parámetro *numeros recoge todos los argumentos que se pasen al llamar la función.
Estos se almacenan en una tupla.
- En el primer ejemplo,
numeros = (3, 5, 9)y el resultado será la suma de esos tres valores (17). - En el segundo,
numeros = (10, 20, 30, 40)y el resultado es100.
Ejemplo práctico: concatenar cadenas
def concatenar(*palabras):
"""Une todas las palabras en una sola cadena separada por espacios."""
resultado = " ".join(palabras)
return resultado
print(concatenar("Hola", "mundo"))
print(concatenar("Python", "es", "genial"))
Una función puede tener parámetros fijos y además un conjunto de argumentos arbitrarios.
Los parámetros definidos al principio se asignan primero, y los restantes se agrupan en la tupla *args.
def mostrar_info(nombre, *hobbies):
"""Muestra el nombre y la lista de aficiones de una persona."""
print(f"Nombre: {nombre}")
for h in hobbies:
print(f" - {h}")
mostrar_info("Laura", "leer", "correr", "viajar")
- El primer argumento (
"Laura") se asigna al parámetro fijonombre. - Los demás (
"leer","correr","viajar") se agrupan en la tuplahobbies. - La función recorre esa tupla con un bucle
fory muestra cada afición.
2️⃣ Argumentos con nombre arbitrarios (**kwargs)
Cuando se anteponen dos asteriscos ** a un parámetro, Python agrupa todos los argumentos con nombre en un diccionario.
Cada par clave-valor representa el nombre del argumento y su valor asociado.
Sintaxis general
def mostrar_datos(**info):
"""Muestra los pares clave:valor recibidos."""
for clave, valor in info.items():
print(f"{clave}: {valor}")
mostrar_datos(nombre="Ana", edad=25, ciudad="Madrid")
- Todos los argumentos con nombre (
nombre,edad,ciudad) se almacenan dentro del diccionarioinfo. - Por tanto,
info = {'nombre': 'Ana', 'edad': 25, 'ciudad': 'Madrid'}. - El método
.items()permite recorrer las claves y sus valores para mostrarlos uno a uno.
Ejemplo práctico
def perfil_usuario(**datos):
"""Devuelve una descripción a partir de la información del usuario."""
nombre = datos["nombre"]
edad = datos["edad"]
ciudad = datos.get("ciudad", "Ciudad no especificada")
return f"{nombre} ({edad} años) - {ciudad}"
print(perfil_usuario(nombre="Carlos", edad=30))
print(perfil_usuario(nombre="Lucía", edad=22, ciudad="Sevilla"))
La función perfil_usuario() toma cualquier conjunto de datos con nombre.
Usa las claves nombre y edad, y accede a ciudad con .get() para ofrecer un valor alternativo si no existe.
De esta manera se genera una descripción flexible del usuario.
3️⃣ Combinación de *args y **kwargs
Ambos mecanismos pueden combinarse en una misma función. Esto permite recibir simultáneamente argumentos posicionales arbitrarios y con nombre.
Ejemplo general
def resumen(*args, **kwargs):
"""Muestra todos los argumentos recibidos, tanto posicionales como con nombre."""
print("Argumentos posicionales:", args)
print("Argumentos con nombre:", kwargs)
resumen(10, 20, 30, nombre="Ana", edad=25)
args almacena los valores posicionales en una tupla: (10, 20, 30).
kwargs almacena los pares con nombre en un diccionario: {'nombre': 'Ana', 'edad': 25}.
Esta técnica hace que la función sea muy flexible.
El orden de los distintos tipos de parámetros en una definición debe seguir una secuencia específica.
def ejemplo(a, b, *args, clave1, clave2="X", **kwargs):
pass
- Parámetros posicionales normales (
a,b) - Argumentos posicionales arbitrarios (
*args) - Parámetros con nombre obligatorios (
clave1) - Parámetros con nombre con valor por defecto (
clave2="X") - Argumentos con nombre arbitrarios (
**kwargs)
Este orden evita errores en la asignación de argumentos durante la llamada.
Ejemplo práctico
def registrar_evento(usuario, *acciones, nivel="INFO", **detalles):
"""Registra información sobre una acción realizada por un usuario."""
print(f"Usuario: {usuario}")
print(f"Nivel: {nivel}")
print("Acciones:")
for accion in acciones:
print(f" - {accion}")
print("Detalles adicionales:")
for clave, valor in detalles.items():
print(f" {clave}: {valor}")
registrar_evento("admin", "login", "borrar_datos", nivel="ALERTA", ip="192.168.1.2", hora="12:45")
Esta función combina todos los tipos de argumentos posibles:
usuarioes un parámetro fijo.*accionesagrupa las operaciones realizadas por el usuario.niveltiene un valor por defecto.**detallesalmacena la información adicional, como la IP o la hora.
El resultado muestra toda la información de manera ordenada.
4️⃣ Desempaquetado de colecciones
Python permite utilizar los operadores * y ** también al llamar a una función.
En este caso, sirven para desempaquetar una lista, tupla o diccionario y pasar sus elementos como argumentos individuales.
🟩 Desempaquetado de listas o tuplas
def multiplicar(a, b, c):
"""Multiplica tres valores."""
return a * b * c
valores = (2, 3, 4)
print(multiplicar(*valores)) # 24
- El operador
*en la llamada expande la tupla(2, 3, 4)en tres argumentos posicionales. - La función recibe los valores como si se hubiera escrito directamente
multiplicar(2, 3, 4).
🟦 Desempaquetado de diccionarios
def mostrar_persona(nombre, edad, ciudad):
"""Muestra los datos de una persona."""
print(f"{nombre} ({edad}) - {ciudad}")
datos = {"nombre": "Laura", "edad": 29, "ciudad": "Madrid"}
mostrar_persona(**datos)
- El operador
**desempaqueta el diccionariodatosy pasa cada par clave:valor como argumento con nombre. - Esto equivale exactamente a escribir
mostrar_persona(nombre="Laura", edad=29, ciudad="Madrid").
5️⃣ Aplicaciones prácticas
🟩 Procesamiento de operaciones variables
def producto_total(*numeros):
"""Calcula el producto de todos los números proporcionados."""
resultado = 1
for n in numeros:
resultado *= n
return resultado
print(producto_total(2, 3))
print(producto_total(1, 2, 3, 4, 5))
El parámetro *numeros permite multiplicar cualquier cantidad de valores.
En la primera llamada se calculan 2 * 3 = 6, y en la segunda 1 * 2 * 3 * 4 * 5 = 120.
🟦 Construcción dinámica de mensajes
def construir_mensaje(**partes):
"""Construye un mensaje a partir de pares clave:valor."""
mensaje = []
for clave, valor in partes.items():
mensaje.append(f"{clave.upper()}: {valor}")
return " | ".join(mensaje)
print(construir_mensaje(usuario="admin", estado="activo", rol="supervisor"))
Cada par clave:valor se convierte en texto, y luego se unen todos con " | ".
Es útil para generar cadenas dinámicas y bien formateadas.
📊 Tabla resumen
| Tipo de argumento | Símbolo | Tipo de datos que recibe | Forma de acceso | Ejemplo |
|---|---|---|---|---|
| Posicional arbitrario | *args | Tupla de valores | Iteración directa | for n in args: |
| Con nombre arbitrario | **kwargs | Diccionario clave:valor | .items() | for k,v in kwargs.items(): |
Los argumentos arbitrarios (*args, **kwargs) permiten crear funciones más versátiles y adaptables, capaces de recibir cualquier número y tipo de parámetros sin perder legibilidad ni control.